package com.simtek.simplayer.controller;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;

import android.annotation.SuppressLint;
import android.os.AsyncTask;
import android.util.Log;

import com.simtek.simplayer.controller.FetchUrlAsyncTask.FetchUrlCallbackEntity;
import com.simtek.simplayer.utils.Charsets;

public class FetchUrlAsyncTask extends AsyncTask<FetchUrlCallbackEntity, Void, FetchUrlCallbackEntity> {
	public interface FetchUrlCallback {
		public void receiveJS(String js);
	}

	public static class FetchUrlCallbackEntity {
		public String			httpURL, callbackId;
		public String			method;
		public String			postData;
		public String[]			headers;

		public String			jsString;

		public FetchUrlCallback	listener;
	}

	public static final String[]					BROWSER_HEADERS	= {
			"User-Agent",
			"Mozilla/5.0 (Linux; U; Android 2.2; en-us; DROID2 GLOBAL Build/S273) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
			"Accept", "text/plain, text/html",
			"Accept-Charset", "UTF-8,*;q=0.5",
			"Accept-Language", "en-US,en;q=0.8,vi;q=0.6,fr-FR;q=0.4,fr;q=0.2"
																	};

	private static List<String>						COOKIE_KEYS		= Arrays.asList("expires", "domain", "path", "secure", "httponly");
	private static Map<String, Map<String, String>>	WEB_COOKIES		= new HashMap<String, Map<String, String>>();

	@SuppressLint("DefaultLocale")
	@Override
	protected FetchUrlCallbackEntity doInBackground(FetchUrlCallbackEntity... params) {
		FetchUrlCallbackEntity entity = params[0];
		String httpUrl = entity.httpURL;
		String callbackId = entity.callbackId;
		String[] headers = entity.headers;

		String html = "";
		HttpURLConnection conn = null;
		InputStream inStream = null;
		OutputStream output = null;
		try {
			/**
			 * Normalize url
			 */
			URL url = new URL(httpUrl);

			conn = (HttpURLConnection) url.openConnection();
			conn.setInstanceFollowRedirects(true);
			conn.setConnectTimeout(10000);
			conn.setReadTimeout(10000);

			String host = url.getHost();
			conn.setRequestProperty("Host", host);

			for (int i = 0, n = BROWSER_HEADERS.length / 2; i < n; i++) {
				conn.setRequestProperty(BROWSER_HEADERS[2 * i], BROWSER_HEADERS[2 * i + 1]);
			}

			String clientCookie = null;
			if (headers != null && headers.length > 0) {
				for (int i = 0, n = headers.length / 2; i < n; i++) {
					if ("Cookie".equals(headers[2 * i])) {
						clientCookie = headers[2 * i + 1];
						continue;
					}
					conn.setRequestProperty(headers[2 * i], headers[2 * i + 1]);
				}
			} else {
				conn.setRequestProperty("Referer", "http://" + host + "/");
			}

			Map<String, String> cookies = WEB_COOKIES.get(host);
			if (clientCookie != null) {
				StringBuilder cookie = new StringBuilder();
				if (clientCookie != null) {
					cookie.append(clientCookie);
				}

				if (cookies != null) {
					for (Entry<String, String> entry : cookies.entrySet()) {
						cookie.append(entry.getKey()).append("=").append(entry.getValue()).append(";");
					}
				}

				conn.setRequestProperty("Cookie", cookie.toString());
			}

			if (entity.method != null) {
				conn.setRequestMethod(entity.method);
			}

			if (entity.postData != null || "POST".equalsIgnoreCase(entity.method)) {
				conn.setDoOutput(true);
				if (entity.postData != null) {
					output = conn.getOutputStream();
					output.write(entity.postData.getBytes());
					output.flush();
				}
			}
			
			inStream = conn.getInputStream();

			/**
			 * Cookie changed
			 */
			String setCookie = conn.getHeaderField("Set-Cookie");
			if (setCookie != null && setCookie.length() > 0) {
				if (cookies == null) {
					cookies = new HashMap<String, String>();
					WEB_COOKIES.put(host, cookies);
				}

				String[] parts = setCookie.split("[;=]");

				int i = 0;
				while (i < parts.length) {
					if (COOKIE_KEYS.contains(parts[i].toLowerCase().trim())) {
						break;
					}
					cookies.put(parts[i], parts[i + 1]);
					i = i + 2;
				}
			}

			String contentEncoding = conn.getContentEncoding();
			if (contentEncoding != null && contentEncoding.indexOf("gzip") != -1) {
				Log.d("fetch", "Zip!");
				inStream = new GZIPInputStream(inStream);
			}

			BufferedReader in = new BufferedReader(new InputStreamReader(inStream, Charsets.UTF_8));

			StringBuffer buffer = new StringBuffer();

			String inputLine;
			while ((inputLine = in.readLine()) != null) {
				buffer.append(inputLine);
			}
			html = buffer.toString();
		} catch (Throwable e) {
			Log.d("down", httpUrl, e);
		} finally {
			try {
				conn.disconnect();
			} catch (Throwable e2) {
			}
			try {
				inStream.close();
			} catch (Throwable e2) {
			}

			if (output != null) {
				try {
					output.close();
				} catch (Throwable logOrIgnore) {
				}
			}
		}

		html = html.replaceAll("[\n\r]", "").replaceAll("[\\s]+", " ").replace("\"", "\\\"");

		String js = "javascript:BUMAPI_resultForCallback(" + callbackId + ", \"" + html + "\")";
		entity.jsString = js;
		return entity;
	}

	@Override
	protected void onPostExecute(FetchUrlCallbackEntity result) {
		if (null != result.jsString) {
			if (null != result.listener) {
				result.listener.receiveJS(result.jsString);
			}
		}
	}

}
